/*
 * サンプル (dwarf.c)
 * enemy-unit 1 Made by M.
 * 一定条件がそろうと、自殺してしまう。
 * スピードを徐々にあげて、敵が近付いたら逃げるアルゴリズム
 */
#include <system.h>
#include <v93.h>
#include <common.h>
#include "spec.h"
#include "service.h"
#include "vardecl.h"

#define DWARF_MIN_SPEED   (0.058) /* これ以下のスピードならアクセル */
#define DWARF_LIMIT_SPEED (0.060) /* これ以上のスピードならブレーキ */
#define DWARF_LIMIT_DIST  (1.500) /* これ以下に近付いたら逃げる */
#define DWARF_DOWN_SPEED  (0.005) /* 曲がるときにこれ以上なら減速する */
#define DWARF_ENEMY_DIST  (4.000) /* 敵までの距離がこれ以下なら行動をかえる */

/* #undef VERBOSE を #define VERBOSE にすると状況を説明してくれます */
/* デバッグする時に便利です */

#undef VERBOSE

typedef enum {          /* 方向をenumで宣言しておく */
  D_FRONT,
  D_BACK,
  D_LEFT,
  D_RIGHT,
  D_NULL
}DIR;

DIR DwarfBrain(int);    /* 敵を無視した場合の思考ルーチンの宣言 */

/*
--------------------------------------------------------------
 * メインルーチン
 * 注意点：ループは作らない。
 *       一連の動作で、S_TurnLeft,S_TurnRight等は１度だけ呼ぶ
--------------------------------------------------------------
 */
void
DwarfMain(int which)
{
  int         iLRflag;
  int         iFBflag;
  QuadDist    *qDistance;
  direct_t    EnemyDir;
  distance    EnemyDist;
  static char TurnDir = D_LEFT;

  iFBflag = D_NULL;
  iLRflag = D_NULL;
  qDistance = S_CheckDist(which);

/* -------------------------- */
/* 早すぎたらスピードを落とす */
/* -------------------------- */
  if (S_GetSpeed(which) >= DWARF_LIMIT_SPEED){
    iFBflag = D_BACK;
  }
/* ------------------------------ */
/* 進行方向の端が近かったら逃げる */
/* ------------------------------ */
  if(qDistance->dFrontDist < DWARF_LIMIT_DIST){
    /* 一定速度まで落として・・・ */
    if (S_GetSpeed(which) >= DWARF_DOWN_SPEED){
      iFBflag = D_BACK;
    }
    /* 落ちないと思われる方向に曲がる */
    iLRflag = DwarfBrain(which);
#ifdef VERBOSE
    pio_putstr("まずい");
    if (iLRflag == D_LEFT)
      pio_putstr(" 左に逃げよう\n");
    else
      pio_putstr(" 右に逃げよう\n");
#endif
  } else
/* ---------------------------------- */
/* 前以外の端が近かった時に端を避ける */
/* ---------------------------------- */
  /* 左側に端が接近していたら、右に曲がる */
  if(qDistance->dLeftDist < DWARF_LIMIT_DIST){ iLRflag = D_RIGHT; } else

  /* 右側に端が接近していたら、左に曲がる */
  if(qDistance->dRightDist < DWARF_LIMIT_DIST){ iLRflag = D_LEFT; } else

  /* 後ろが近かったらスピードをあげる */
  if (qDistance->dBackDist < DWARF_LIMIT_DIST){ iFBflag = D_FRONT; } else
/* ---------------------------------------- */
/* 進行方向の端が近くなかったら、敵を探す   */
/*                                          */
/* EnemyDir : 敵のいる方角（0.1°単位)      */
/* EnemyDist: 敵までの距離 MIN < dist < MAX */
/* ---------------------------------------- */
  {
    EnemyDir = S_SearchEnemy(which);    
    EnemyDist = S_CalcEnemyDist(which); 

    /* 見つからなかった場合（後ろにいた場合）*/
    if (EnemyDir < 0) {
      /* 落ちない方向を探して曲がる */
      iLRflag = DwarfBrain(which);
#ifdef VERBOSE
      pio_putstr("どこ？");
      if (iLRflag == D_LEFT)
        pio_putstr(" 左かな？\n");
      else
        pio_putstr(" 右かな？\n");
#endif
    } else {
    /* 敵が前にいた場合 */
      /* 一定以内の距離にいた場合 */
      if (EnemyDist <= DWARF_ENEMY_DIST) {
#ifdef VERBOSE
      pio_putstr("近い!\n");
#endif
        /* 敵のいない方角に曲がる */
        if (EnemyDir > 1800)
          iLRflag = D_LEFT;
        else
          iLRflag = D_RIGHT;
      } else {
      /* 敵が前にいるけど、ある程度離れていた場合 */
      /* そのまま進む */
        iLRflag = D_NULL;
        /* 前方１０°以内にいた場合 */
        if (EnemyDir <= 100 || EnemyDir >= 3500) {
          /* 敵のいる方角に曲がる */
          if (EnemyDir > 1800)
            iLRflag = D_RIGHT;
          else
            iLRflag = D_LEFT;
        } else {
         /* 前方６０°以内にいた場合 */
          if (EnemyDir <= 300 || EnemyDir >= 3300) {
            /* リミットスピードに達していない場合(最速まで) */
            if (S_GetSpeed(which) <= DWARF_LIMIT_SPEED) {
              /* スピードをあげる */
              iFBflag = D_FRONT;
            }
          }
        }
      }
    }
    /* 遅かったらスピードをあげる(普段のスピードまで) */
    if (S_GetSpeed(which) <= DWARF_MIN_SPEED) {
      iFBflag = D_FRONT;
    }
  }
/* ---------------------------------------------- */
/* 決定された行動パターンから、実際に行動にうつす */
/* ---------------------------------------------- */
  switch(iLRflag){
    case D_LEFT:    /* 左 */
      S_TurnLeft(which);
      break;
    case D_RIGHT:   /* 右 */
      S_TurnRight(which);
      break;
    default:
      break;
  }
  switch(iFBflag){
    case D_FRONT:   /* 前 */
      S_Forward(which);
      break;
    case D_BACK:    /* ブレーキ */
      S_Backward(which);
      break;
    default:
      break;
  }
}

/*
----------------------------------------
 * 曲がる方向を考えるルーチン
 * 落ちない方向を探し出す。
----------------------------------------
 */
DIR
DwarfBrain(int which)
{
  float     fMyX,fMyY;
  direct_t  dtMyDir;
  DIR       DWhich;

  /* 自分の情報を拾う */
  /* 角度は0.1°単位なので、10で割る */
  /* 内部でのＸＹ座標と角度は、Ｘ＝０の線を０°として
     扱っているので変換を行う */
  fMyX = -1 * S_CheckY(which);
  fMyY = S_CheckX(which);
  dtMyDir = (direct_t)(S_CheckDir(which) / 10);

  /* フィールドを４５°単位で８分割し、
     場所と向きによって曲がる方向を決める */
  if( fMyX > 0 && fMyY > 0 ){
    if( fMyX > fMyY ){
/* 1 */
      if(dtMyDir > 0 && dtMyDir < 180)
        DWhich = D_LEFT;
      else
        DWhich = D_RIGHT;
    } else {
/* 2 */
      if(dtMyDir < 90 || dtMyDir > 270 )
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    }
  }
  else
  if( fMyX < 0 && fMyY > 0 ){
    if( abs(fMyX) > abs(fMyY) ){
/* 4 */
      if(dtMyDir > 0 && dtMyDir < 180)
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    } else {
/* 3 */
      if(dtMyDir < 90 || dtMyDir > 270 )
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    }
  }
  else
  if( fMyX < 0 && fMyY < 0 ){
    if( fMyX > fMyY ){
/* 6 */
      if(dtMyDir < 90 || dtMyDir > 270)
        DWhich = D_LEFT;
      else
        DWhich = D_RIGHT;
    } else {
/* 5 */
      if(dtMyDir > 0 && dtMyDir < 180)
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    }
  } else {
    if( fMyX > 0 && fMyY < 0 ){
      if( abs(fMyX) < abs(fMyY) ){
/* 7 */
        if(dtMyDir > 0 && dtMyDir < 180)
          DWhich = D_RIGHT;
        else
          DWhich = D_LEFT;
       } else {
/* 8 */
        if(dtMyDir < 90 || dtMyDir > 270)
          DWhich = D_LEFT;
        else
          DWhich = D_RIGHT;
      }
    } else {
      DWhich = D_RIGHT;
    }
  }
  return DWhich;
}
